package main

// 函数声明包括函数名、形式参数列表、返回值列表（可省略）以及函数体。
/*
func name(parameter-list) (result-list) {
    body
}
*/
//形式参数列表描述了函数的参数名以及参数类型。这些参数作为局部变量，其值由参数调用者提供。
//返回值列表描述了函数返回值的变量名以及类型。
//如果函数返回一个无名变量或者没有返回值，返回值列表的括号是可以省略的。
//如果一个函数声明不包括返回值列表，那么函数体执行完毕后，不会返回任何值。 在hypot函数中,

// 匿名函数
// 有函数名的函数只能在包级语法块中被声明，通过函数字面量（function literal），我们可绕过这一限制，在任何表达式中表示一个函数值。函数字面量的语法和函数声明相似，区别在于func关键字后没有函数名。函数值字面量是一种表达式，它的值被称为匿名函数（anonymous function）。
// 函数字面量允许我们在使用函数时，再定义它。通过这种技巧，我们可以改写之前对strings.Map的调用：
// strings.Map(func(r rune) rune { return r + 1 }, "HAL-9000")

import (
	"fmt"
	"math"
)

func hyport(x, y float64) (z float64) {
	z = math.Sqrt(x*x + y*y)
	return z
}

func add(x int, y int) int   { return x + y }
func sub(x, y int) (z int)   { z = x - y; return }
func first(x int, _ int) int { return x }
func zero(int, int) (int, int) {
	return 0, 0
}

// 在Go中，函数被看作第一类值（first-class values）：函数像其他值一样，拥有类型，可以被赋值给其他变量，传递给函数，从函数返回。对函数值（function value）的调用类似函数调用。例子如下：

func square(n int) int     { return n * n }
func negative(n int) int   { return -n }
func product(m, n int) int { return m * n }

func sum(vals ...int) int {
	total := 0
	for _, val := range vals {
		total += val
	}
	return total
}

func main() {
	fmt.Println("eee")
	fmt.Println(hyport(3, 4))
	fmt.Printf("%T\n", add)   // "func(int, int) int"
	fmt.Printf("%T\n", sub)   // "func(int, int) int"
	fmt.Printf("%T\n", first) // "func(int, int) int"
	fmt.Printf("%T\n", zero)  // "func(int, int) int"
	f := square
	fmt.Println(f(3)) // "9"

	f = negative
	fmt.Println(f(3))     // "-3"
	fmt.Printf("%T\n", f) // "func(int) int"

	// f = product // compile error: can't assign func(int, int) int to func(int) int
	fmt.Println(sum(4, 5, 6))
	values := []int{1, 2, 3}
	fmt.Println(sum(values...))

}
